package com.maas.util.mybatis.jpa.littlenb.statement;

import com.littlenb.mybatisjpa.statement.AbstractStatementFactory;
import com.littlenb.mybatisjpa.statement.StatementFactory;
import com.littlenb.mybatisjpa.support.Constant;
import com.littlenb.mybatisjpa.type.SelectorStrategy;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.DeleteDefinition;
import com.maas.util.mybatis.jpa.littlenb.constant.ResultMapConstants;
import com.maas.util.mybatis.jpa.littlenb.meta.PersistentMeta;
import com.maas.util.mybatis.jpa.littlenb.support.core.MyMybatisStatementAdapter;
import com.maas.util.mybatis.jpa.littlenb.support.template.delete.DeleteCertainSqlTemplate;
import com.maas.util.mybatis.jpa.littlenb.support.template.delete.DeleteIgnoreNullSqlTemplate;
import com.maas.util.mybatis.jpa.littlenb.support.template.delete.DeleteSqlTemplate;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;

import java.lang.reflect.Method;

/**
 * @select 扫描器
 * 修改自 mybatis-jba
 * @author sway.li ->zxm
 */
public class DelectStatementFactory extends AbstractStatementFactory implements MyStatementBuildable {

  public static final StatementFactory INSTANCE = new DelectStatementFactory();
  MyMybatisStatementAdapter adapter;

  /**
   * 返回MappedStatement 用于mybatis 的configuration.addMappedStatement(statement);
   * @param configuration
   * @param method
   * @param targetClass
   * @return
   */
  @Override
  public MappedStatement parseStatement(Configuration configuration, Method method,
      Class<?> targetClass) {
    String resourceName = targetClass.toString();

    if (!configuration.isResourceLoaded(resourceName)) {
      configuration.addLoadedResource(resourceName);
    }
    String targetClassName = targetClass.getName();
    Class<?> type = super.recognizeEntityType(method, targetClass);
    LanguageDriver languageDriver = Constant.XML_LANGUAGE_DRIVER;
    SqlSource sqlSource = languageDriver
        .createSqlSource(configuration, "<script> " + parsesql(method, type) + "</script>",
            Object.class);


    String statementId = targetClassName + "." + method.getName();

    //MappedStatement 建构器
    MappedStatement.Builder builder = new MappedStatement.Builder(configuration, statementId,
        sqlSource, SqlCommandType.DELETE);


    //builder.resultSetType(getResultSetType());

    //预编译
    builder.resource(super.recognizeResource(targetClassName)).lang(languageDriver)
        .statementType(StatementType.PREPARED);



    MappedStatement mappedStatement = builder.build();
    return mappedStatement;
  }


  /**
   * 生成sql
   * @param method
   * @param type
   * @return
   */
  private String parsesql(Method method, Class<?> type) {
    DeleteDefinition definition = method.getAnnotation(DeleteDefinition.class);
    if (definition == null) {
      throw new RuntimeException(
              "'" + method.getName() + "' method is not annotation with 'DeleteDefinition'.");
    }
    SelectorStrategy strategy = definition.strategy();

    String sql = "";

    //通过模板和注解构建sql语句
    sql = DeleteSqlTemplate.INSTANCE.parseSQL(type);

    //TODO 动态生成 where 语句
    if (SelectorStrategy.IGNORE_NULL.equals(strategy)) {
      sql += "" + DeleteIgnoreNullSqlTemplate.INSTANCE.parseSQL(type);
    }else if (SelectorStrategy.CERTAIN.equals(strategy)) {
      sql +=  DeleteCertainSqlTemplate.INSTANCE.parseSQL(type);
    }else{
      //where
      if (!"".equals(definition.where())) {
        sql = sql + " where " + definition.where();
      }
    }

    return sql;
  }

  private SelectorStrategy recognizeStrategy(Method method) {
    DeleteDefinition definition = method.getAnnotation(DeleteDefinition.class);
    if (definition == null) {
      throw new RuntimeException(
          "'" + method.getName() + "' method is not annotation with 'DeleteDefinition'.");
    }
    return definition.strategy();
  }

  @Override
  public String buildSQL(PersistentMeta persistentMeta, Method method) {

    Class<?> type = super.recognizeEntityType(method, adapter.getMapper());
    //return  parseSQL(method, type);
    return "<script> " + parsesql(method, type) + "</script>";

  }

  @Override
  public void parseStatement(MyMybatisStatementAdapter adapter, PersistentMeta persistentMeta, Method method) {
    this.adapter = adapter;
    // 方法名
    adapter.setMethodName(method.getName());
    // 参数类型
    if (method.getParameterTypes().length > 0) {
      // Mybatis mapper 方法最多支持一个参数,先设置成Object.class,mybatis会在sql中解析
      adapter.setParameterTypeClass(Object.class);
    } else {
      adapter.setParameterTypeClass(void.class);
    }



    // sqlScript
    adapter.setSqlScript(buildSQL(persistentMeta, method));
    // 返回值类型
    adapter.setResultType(persistentMeta.getType());
    //resultmap
    adapter.setResultMapId(ResultMapConstants.DEFAULT_NAMESPACE + "." + persistentMeta.getEntityName());

    adapter.setSqlCommandType(SqlCommandType.SELECT);

    // 主键策略
    adapter.setKeyGenerator(new NoKeyGenerator());
    adapter.setKeyProperty(null);
    adapter.setKeyColumn(null);

    //修改sql驱动
    adapter.setLanguageDriver(Constant.XML_LANGUAGE_DRIVER);
    adapter.parseStatement();
  }

}
